package com.wg.net.server.http;

import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wg.core.io.IBinaryReader;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.QueryStringDecoder;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * 增强版HTTP请求对象，支持完整内容类型解析、线程安全和详细日志
 *
 * @author 少爷123
 */
public class HttpServletRequest {
    private static final Log log = LogFactory.get();
    /**
     * 请求参数映射表（线程安全）
     */
    private final ConcurrentHashMap<String, List<String>> parameterMap = new ConcurrentHashMap<>();
    /**
     * 请求ID
     */
    private final String id;
    /**
     * 请求URI
     */
    private final String uri;
    /**
     * 请求方法
     */
    private final String method;
    /**
     * 请求IP
     */
    private final String ip;
    /**
     * 处理时间间隔
     */
    private final TimeInterval handleInterval = new TimeInterval(true);
    /**
     * 请求头映射表
     */
    private final Map<String, String> headersMap = new ConcurrentHashMap<>();
    /**
     * 请求体读取器
     */
    private IBinaryReader bodyReader;

    HttpServletRequest(String uri, HttpMethod method, String ip, String id) {
        this.uri = uri;
        this.ip = ip;
        this.method = method.name();
        this.id = id;
    }

    public String getUri() {
        return uri;
    }

    public String getParameter(String name) {
        List<String> values = parameterMap.get(name);
        return (values != null && !values.isEmpty()) ? values.get(0) : null;
    }

    public Enumeration<String> getParameterNames() {
        return Collections.enumeration(parameterMap.keySet());
    }

    public String[] getParameterValues(String name) {
        List<String> values = parameterMap.get(name);
        return (values != null) ? values.toArray(new String[0]) : new String[0];
    }

    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> result = new HashMap<>(parameterMap.size());
        parameterMap.forEach((k, v) -> result.put(k, v.toArray(new String[0])));
        return result;
    }

    public String getHeader(String name) {
        return headersMap.get(name);
    }

    public Map<String, String> headers() {
        return new HashMap<>(headersMap);
    }

    public String getRemoteAddr() {
        return ip;
    }

    public String getMethod() {
        return method;
    }

    public String getId() {
        return id;
    }

    public IBinaryReader getBodyReader() {
        return bodyReader;
    }

    public TimeInterval getHandleInterval() {
        return handleInterval;
    }

    /**
     * 解析请求参数
     *
     * @param fhr     Netty的FullHttpRequest对象
     * @param decoder URI参数解析器
     * @throws IOException 解析失败时抛出
     */
    public void parse(FullHttpRequest fhr, QueryStringDecoder decoder) throws IOException {
        final HttpMethod method = fhr.method();
        final HttpHeaders headers = fhr.headers();

        // 解析请求头（线程安全）
        headers.forEach(entry -> headersMap.put(entry.getKey(), entry.getValue()));

        // 解析URI参数（GET/HEAD请求）
        if (HttpMethod.GET == method || HttpMethod.HEAD == method) {
            parseGetRequestParameter(decoder);
        }

        // 解析请求体（POST/PUT等有body的请求）
        if (hasRequestBody(method)) {
            parseRequestBody(fhr, method);
        }

        log.debug("请求解析完成 | ID: {}, URI: {}, 方法: {}, 参数数量: {}",
                id, uri, method, parameterMap.size());
    }

    /**
     * 判断请求是否包含Body（根据HTTP方法）
     */
    private boolean hasRequestBody(HttpMethod method) {
        return HttpMethod.POST == method || HttpMethod.PUT == method || HttpMethod.PATCH == method;
    }

    /**
     * 解析请求体内容（核心逻辑）
     */
    private void parseRequestBody(FullHttpRequest fhr, HttpMethod method) throws IOException {
        String contentType = fhr.headers().get(HttpHeaderNames.CONTENT_TYPE, "");
        ByteBuf content = fhr.content();

        try {
            if (contentType.startsWith("application/json")) {
                parseJsonContent(content);
            } else if (contentType.startsWith("application/x-www-form-urlencoded")) {
                parseFormUrlEncodedContent(content);
            } else if (contentType.startsWith("multipart/form-data")) {
                log.error("不支持multipart/form-data");
            } else if (contentType.startsWith("text/xml") || contentType.startsWith("application/xml")) {
                parseXmlContent(content); // 新增XML支持
            } else {
                parseRawContent(content);
            }
        } catch (Exception e) {
            log.error("请求体解析失败 | URI: {}, 方法: {}, Content-Type: {}, 异常: {}",
                    uri, method.name(), contentType, e.getMessage(), e);
            throw new IOException("请求体解析失败: " + e.getMessage(), e);
        }
    }

    /**
     * 解析JSON内容（增强异常处理）
     */
    private void parseJsonContent(ByteBuf content) {
        if (content.readableBytes() == 0) {
            log.warn("JSON内容为空，跳过解析");
            return;
        }

        try {
            String json = content.toString(StandardCharsets.UTF_8);
            JSONObject jsonObject = JSON.parseObject(json);
            jsonObject.forEach((key, value) -> {
                String strValue = (value != null) ? value.toString() : "";
                parameterMap.computeIfAbsent(key, k -> new ArrayList<>()).add(strValue);
            });
            log.debug("JSON解析完成 | 键数量: {}", jsonObject.size());
        } catch (Exception e) {
            log.error("JSON解析失败 | 内容: {}", content.toString(StandardCharsets.UTF_8), e);
            throw new RuntimeException("JSON解析失败: " + e.getMessage(), e);
        }
    }

    /**
     * 解析表单数据（application/x-www-form-urlencoded）
     */
    private void parseFormUrlEncodedContent(ByteBuf content) {
        if (content.readableBytes() == 0) {
            log.warn("表单内容为空，跳过解析");
            return;
        }

        try {
            String body = content.toString(StandardCharsets.UTF_8);
            QueryStringDecoder decoder = new QueryStringDecoder(body, StandardCharsets.UTF_8);
            decoder.parameters().forEach((key, values) -> {
                List<String> existing = parameterMap.computeIfAbsent(key, k -> new ArrayList<>());
                existing.addAll(values);
            });
            log.debug("表单解析完成 | 参数数量: {}", decoder.parameters().size());
        } catch (Exception e) {
            log.error("表单解析失败 | 内容: {}", content.toString(StandardCharsets.UTF_8), e);
            throw new RuntimeException("表单解析失败: " + e.getMessage(), e);
        }
    }

    /**
     * 解析XML内容（支持嵌套节点）
     */
    private void parseXmlContent(ByteBuf content) {
        if (content.readableBytes() == 0) {
            log.warn("XML内容为空，跳过解析");
            return;
        }

        try {
            String xmlStr = content.toString(StandardCharsets.UTF_8);
            Document doc = XmlUtil.parseXml(xmlStr);
            Element root = doc.getDocumentElement();
            traverseXmlNode(root, "", parameterMap);
            log.debug("XML解析完成 | 根节点: {}", root.getNodeName());
        } catch (Exception e) {
            log.error("XML解析失败 | 内容: {}", content.toString(StandardCharsets.UTF_8), e);
            throw new RuntimeException("XML解析失败: " + e.getMessage(), e);
        }
    }

    /**
     * 递归遍历XML节点（深度优先）
     */
    private void traverseXmlNode(Element element, String parentPath, Map<String, List<String>> parameterMap) {
        String currentNodePath = StrUtil.isBlank(parentPath) ? element.getNodeName()
                : parentPath + "." + element.getNodeName();

        // 处理节点文本
        String textContent = element.getTextContent();
        if (StrUtil.isNotBlank(textContent)) {
            parameterMap.computeIfAbsent(currentNodePath, k -> new ArrayList<>()).add(textContent.trim());
        }

        // 处理子节点
        NodeList childNodes = element.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            org.w3c.dom.Node child = childNodes.item(i);
            if (child instanceof Element) {
                traverseXmlNode((Element) child, currentNodePath, parameterMap);
            }
        }
    }

    /**
     * 解析原始内容（如text/plain）
     */
    private void parseRawContent(ByteBuf content) {
        if (content.readableBytes() == 0) {
            log.warn("原始内容为空，跳过解析");
            return;
        }

        String body = content.toString(StandardCharsets.UTF_8);
        parameterMap.computeIfAbsent("rawBody", k -> new ArrayList<>()).add(body);
        log.debug("原始内容解析完成 | 长度: {} 字节", body.length());
    }

    /**
     * 解析GET请求参数（URI中的查询参数）
     */
    private void parseGetRequestParameter(QueryStringDecoder decoder) {
        decoder.parameters().forEach((key, values) -> {
            List<String> existing = parameterMap.computeIfAbsent(key, k -> new ArrayList<>());
            existing.addAll(values);
        });
        log.debug("GET参数解析完成 | 参数数量: {}", decoder.parameters().size());
    }
}